/**
*  \file task.c
*
*  \brief
*
*  \author Dajin Li  <dajin.li@linde-.de>
*
*
*/

/*===============================================[ private includes  ]================================================*/

#include "task.h"
#include "xmc4_flash.h"
#include "deaddrop.h"
#include "deaddrop_bb.h"
#include "../xmc4500/i2c_hw.h"

#include "../xmc4500/can_drv.h"
#include "../can/can_open.h"
#include "../pal/types.h"
#include "../app/bis.h"
#include "../var/var_tbl.h"
#include "../swidft/swidft.h"
#include "../mutabor/mutabor.h"


/*===============================================[ private defines   ]================================================*/
#define FLASH_REQUEST_FLAG                                            0xA5968778

#define FLASH_MAX_SECT                                                12
#define STAY_IN_BOOT_TIME_CONST                                       50
/*===============================================[ private datatypes ]================================================*/

/*===============================================[ private variables ]================================================*/
static s16 start_sector;
static s16 sector_number;

/*===============================================[ public variables ]================================================*/
u8 stay_for_ever;
s16 crc_rv;
u8 flash_data[2048];
u8 send_kwp_msg = 0;


u32 stay_in_boot_time = 50;


static const u32 CRC32_table[] = 
{
    0x00000000,0x04C11DB7,0x09823B6E,0x0D4326D9,0x130476DC,0x17C56B6B,0x1A864DB2,0x1E475005,
    0x2608EDB8,0x22C9F00F,0x2F8AD6D6,0x2B4BCB61,0x350C9B64,0x31CD86D3,0x3C8EA00A,0x384FBDBD,
    0x4C11DB70,0x48D0C6C7,0x4593E01E,0x4152FDA9,0x5F15ADAC,0x5BD4B01B,0x569796C2,0x52568B75,
    0x6A1936C8,0x6ED82B7F,0x639B0DA6,0x675A1011,0x791D4014,0x7DDC5DA3,0x709F7B7A,0x745E66CD,
    0x9823B6E0,0x9CE2AB57,0x91A18D8E,0x95609039,0x8B27C03C,0x8FE6DD8B,0x82A5FB52,0x8664E6E5,
    0xBE2B5B58,0xBAEA46EF,0xB7A96036,0xB3687D81,0xAD2F2D84,0xA9EE3033,0xA4AD16EA,0xA06C0B5D,
    0xD4326D90,0xD0F37027,0xDDB056FE,0xD9714B49,0xC7361B4C,0xC3F706FB,0xCEB42022,0xCA753D95,
    0xF23A8028,0xF6FB9D9F,0xFBB8BB46,0xFF79A6F1,0xE13EF6F4,0xE5FFEB43,0xE8BCCD9A,0xEC7DD02D,
    0x34867077,0x30476DC0,0x3D044B19,0x39C556AE,0x278206AB,0x23431B1C,0x2E003DC5,0x2AC12072,
    0x128E9DCF,0x164F8078,0x1B0CA6A1,0x1FCDBB16,0x018AEB13,0x054BF6A4,0x0808D07D,0x0CC9CDCA,
    0x7897AB07,0x7C56B6B0,0x71159069,0x75D48DDE,0x6B93DDDB,0x6F52C06C,0x6211E6B5,0x66D0FB02,
    0x5E9F46BF,0x5A5E5B08,0x571D7DD1,0x53DC6066,0x4D9B3063,0x495A2DD4,0x44190B0D,0x40D816BA,
    0xACA5C697,0xA864DB20,0xA527FDF9,0xA1E6E04E,0xBFA1B04B,0xBB60ADFC,0xB6238B25,0xB2E29692,
    0x8AAD2B2F,0x8E6C3698,0x832F1041,0x87EE0DF6,0x99A95DF3,0x9D684044,0x902B669D,0x94EA7B2A,
    0xE0B41DE7,0xE4750050,0xE9362689,0xEDF73B3E,0xF3B06B3B,0xF771768C,0xFA325055,0xFEF34DE2,
    0xC6BCF05F,0xC27DEDE8,0xCF3ECB31,0xCBFFD686,0xD5B88683,0xD1799B34,0xDC3ABDED,0xD8FBA05A,
    0x690CE0EE,0x6DCDFD59,0x608EDB80,0x644FC637,0x7A089632,0x7EC98B85,0x738AAD5C,0x774BB0EB,
    0x4F040D56,0x4BC510E1,0x46863638,0x42472B8F,0x5C007B8A,0x58C1663D,0x558240E4,0x51435D53,
    0x251D3B9E,0x21DC2629,0x2C9F00F0,0x285E1D47,0x36194D42,0x32D850F5,0x3F9B762C,0x3B5A6B9B,
    0x0315D626,0x07D4CB91,0x0A97ED48,0x0E56F0FF,0x1011A0FA,0x14D0BD4D,0x19939B94,0x1D528623,
    0xF12F560E,0xF5EE4BB9,0xF8AD6D60,0xFC6C70D7,0xE22B20D2,0xE6EA3D65,0xEBA91BBC,0xEF68060B,
    0xD727BBB6,0xD3E6A601,0xDEA580D8,0xDA649D6F,0xC423CD6A,0xC0E2D0DD,0xCDA1F604,0xC960EBB3,
    0xBD3E8D7E,0xB9FF90C9,0xB4BCB610,0xB07DABA7,0xAE3AFBA2,0xAAFBE615,0xA7B8C0CC,0xA379DD7B,
    0x9B3660C6,0x9FF77D71,0x92B45BA8,0x9675461F,0x8832161A,0x8CF30BAD,0x81B02D74,0x857130C3,
    0x5D8A9099,0x594B8D2E,0x5408ABF7,0x50C9B640,0x4E8EE645,0x4A4FFBF2,0x470CDD2B,0x43CDC09C,
    0x7B827D21,0x7F436096,0x7200464F,0x76C15BF8,0x68860BFD,0x6C47164A,0x61043093,0x65C52D24,
    0x119B4BE9,0x155A565E,0x18197087,0x1CD86D30,0x029F3D35,0x065E2082,0x0B1D065B,0x0FDC1BEC,
    0x3793A651,0x3352BBE6,0x3E119D3F,0x3AD08088,0x2497D08D,0x2056CD3A,0x2D15EBE3,0x29D4F654,
    0xC5A92679,0xC1683BCE,0xCC2B1D17,0xC8EA00A0,0xD6AD50A5,0xD26C4D12,0xDF2F6BCB,0xDBEE767C,
    0xE3A1CBC1,0xE760D676,0xEA23F0AF,0xEEE2ED18,0xF0A5BD1D,0xF464A0AA,0xF9278673,0xFDE69BC4,
    0x89B8FD09,0x8D79E0BE,0x803AC667,0x84FBDBD0,0x9ABC8BD5,0x9E7D9662,0x933EB0BB,0x97FFAD0C,
    0xAFB010B1,0xAB710D06,0xA6322BDF,0xA2F33668,0xBCB4666D,0xB8757BDA,0xB5365D03,0xB1F740B4, 
};



/*===============================================[ private functions ]================================================*/
static void read_params_from_fram(void);
static void getFlashInfo(u32 start_flashAddr, u32 flash_size);


static const flash_sect_st sector_tbl[] =
{
    {0x0C000000U,    0x0C003FFFU},                 // 0  16K
    {0x0C004000U,    0x0C007FFFU},                 // 1  16K
    {0x0C008000U,    0x0C00BFFFU},                 // 2  16K
    {0x0C00C000U,    0x0C00FFFFU},                 // 3  16K
    {0x0C010000U,    0x0C013FFFU},                 // 4  16K
    {0x0C014000U,    0x0C017FFFU},                 // 5  16K
    {0x0C018000U,    0x0C01BFFFU},                 // 6  16K
    {0x0C01C000U,    0x0C01FFFFU},                 // 7  16K
    {0x0C020000U,    0x0C03FFFFU},                 // 8  128K
    {0x0C040000U,    0x0C07FFFFU},                 // 9  256K
    {0x0C080000U,    0x0C0BFFFFU},                 // 10 256K
    {0x0C0C0000U,    0x0C0FFFFFU},                 // 11 256K
};

/*================================================[ inline functions ]================================================*/

/*================================================[ public functions ]================================================*/
s16 EraseFlash(u32 start_addr, u32 length)
{
    u8 i = 0;

    getFlashInfo(start_addr, length); 
    
    if(start_addr + length - 1 > sector_tbl[FLASH_MAX_SECT - 1].sector_end)
    {
        return -1;
    }
    send_kwp_msg = 1;

    __disable_irq();

    for(i = 0; i < sector_number; i++)
    {
        /* 1st step: Erase sector */
        XMC_FLASH_EraseSector((u32 *)sector_tbl[i+start_sector].sector_addr);
    }
    __enable_irq();
    send_kwp_msg = 0;
    return 0;
}

u32 calc_crc32(u32 *src, u32 init_value, u32 length)
{
    u32 crc32Data = init_value;
    u32 i = 0, j = 0;
    u32 u32data = 0;
    u32 crc32TempData = 0;
         
    for(i = 0; i < length; i++)
    {
        u32data = src[i];
        crc32Data ^= u32data;

        for(j = 0; j < 4; j++)
        {
            crc32TempData = CRC32_table[(crc32Data >> 24) & 0xff];
            crc32Data <<= 8;
            crc32Data ^= crc32TempData;
        }
    }
    return crc32Data;
}

void JumpToApp(void)
{
	 struct xmc_vector_table const * const vtab = (void*)ApplicationSWAddress;
     if(*(u32*)(DEADDROP_RAM_ADDR + 56) == VALID_FLAG_VALUE)
     {
        //deadrop_clear_start_application_flag();
        *(u32*)(DEADDROP_RAM_ADDR + 56) = ~VALID_FLAG_VALUE;
        __set_MSP(*(__IO u32*) ApplicationSWAddress);  // Initialize user application's Stack Pointer 
        SCB->VTOR = ApplicationSWAddress;
        vtab->reset();
    }
}

/**
* @brief	It creates and starts all other tasks. 
* @param	none
* @note     none
* @retval   none
*/


void create_tasks(void) 
{
    struct bis *boot_bis = (struct bis *)BootBISAddress;
    u32 crc_32;

    stay_in_boot_time = STAY_IN_BOOT_TIME_CONST;
    send_kwp_msg = 0;

    /*##-1- Configure the CRC peripheral #######################################*/
    crc_32 = calc_crc32((u32 *)boot_bis, CRC_INIT_VALUE, BIS_LEN); // calculat boot software crc
    if(crc_32 != boot_bis->bis_checksum)
    {
        while(1);
    }
    crc_32 = calc_crc32((u32 *)(boot_bis->checksum_start), CRC_INIT_VALUE, boot_bis->checksum_len); // calculat boot software crc
    if(crc_32 != boot_bis->checksum_value)
    {
        while(1);
    }
    i2c_hardware_init();
    swidft_software_id_from_time(boot_bis->build_time, software_id); // get boot software id
    read_params_from_fram(); 
    
    if( deadrop_is_stay_in_bb_flag()) // updated flash from application
    {
        deadrop_clear_stay_in_bb_flag();
        stay_for_ever = 1;
        can_task(); 
    }
    else   // Jump to user application 
    {
        stay_for_ever = 0;
        KWP_send_boot_msg();
        can_task();
        deadrop_set_start_application_flag();
        NVIC_SystemReset();
    }
}


void write_parameter_to_fram(u8 u8Index)
{	
    u8 *char_ptr;
    u8 u8Length;

    if(u8Index < MAX_KWP_DATA_OBJECT_DEF)
    {
        char_ptr = (u8 *) kwp_data_params[ u8Index].var;
        u8Length = kwp_data_params[u8Index].attr & VAR_LENGTH_MASK;
        i2c_master_write(kwp_data_params[u8Index].ee_addr, char_ptr, u8Length);
    }
}


/*===============================================[ private functions ]================================================*/


/**
* @brief	enable read protection.
* @param	none
* @note     none
* @retval   none 
*/
static void getFlashInfo(u32 start_flashAddr, u32 flash_size)
{
    u16 i = 0;
    u32 end_addr = 0;

    for(i = 0; i < FLASH_MAX_SECT; i++)
    {
        if(start_flashAddr <= sector_tbl[i].sector_end)
        {
            break;
        }
    }
    start_sector = i;

    end_addr = start_flashAddr + flash_size - 1;

    for(i = start_sector; i < FLASH_MAX_SECT; i++)
    {
        if(end_addr <=  sector_tbl[i].sector_end)
        {
            break;
        }
    } 
    sector_number = i - start_sector + 1;
}


static void read_params_from_fram(void)
{
    U32 u32Data=0xffffffff; 
    U8 i;
    
    i2c_master_read(0x02, (u8*)hardware_id, 11);  //  read hardware id
    for(i = 0; i < 11; i++)
    {
    	hardware_id[i] += 0x30;
    }

    hardware_id[11] = 0x00;

    //sd_read(&fram.sd, &u32Data, 0x1FF4, 4);  //  read applicaton software id
    swidft_software_id_from_time(u32Data, software_id_first_start); // convert to string
    
    i2c_master_read(0x0E, (u8*)part_number, 11);  //  part number
    for(i = 0; i < 11; i++)
    {
    	part_number[i] += 0x30;
    }
    part_number[11] = 0x00;
    
    i2c_master_read(0x1A, (u8*)last_part_number, 11);  //  last part number
    for(i = 0; i < 11; i++)
    {
    	last_part_number[i] += 0x30;
    }
    last_part_number[11] = 0x00;

    i2c_master_read(0x26,  (u8*)&serial_number, 15);  //   serial number
    serial_number[15] = 0x00;

    i2c_master_read(0x36,  (u8*)&brand_id, 2);  //   brand id

    i2c_master_read(0x38, (u8*)ecu_name, 15);  //  ecu_name
    ecu_name[15] = 0x00;
    
}

/***********************************************************************************************************************
*                             Copyright 2016 Linde Material Handling. All rights reserved.                             *
***********************************************************************************************************************/

